package com.xbongbong.paas.field;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.enums.DateTimeEnum;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.saas.enums.NumberTypeEnum;
import com.xbongbong.saas.enums.business.ContractEnum;
import com.xbongbong.saas.enums.business.PurchaseEnum;
import com.xbongbong.saas.enums.business.QuotationEnum;
import com.xbongbong.saas.enums.business.SalesOpportunityEnum;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.i18n.LocaleContextHolder;

import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.io.Serializable;
import java.util.List;
import java.util.Locale;
import java.util.Objects;

/**
 * @author wufeng
 * @date 2018/8/14 16:34
 * @desrcption 表单字段属性
 */
@Getter
@Setter
@ToString
public class FieldAttrEntity implements Serializable, Comparable<FieldAttrEntity>  {

    private static final long serialVersionUID = 809543324330867244L;

    /**
     * 字段id，用于区分字段先后生成attr一致的区分
     */
    private String fieldId;
    /**
     * 唯一标识，低代码使用
     */
    private String uniquelyId;

    /**
     * 表单id
     */
    private Long formId;
    /**
     * 字段
     */
    @NotBlank(message = "字段标识不能为空")
    private String attr;
    /**
     * 字段依赖 -上级字段Attr
     */
    private String superAttr;
    /**
     *多表下的原attr
     **/
    private String originalAttr;
    /**
     * 父类attr，用于子表单存储子字段存储父字段
     */
    private String parentAttr;
    /**
     * 字段标识索引
     */
    @NotBlank(message = "字段标识索引不能为空")
    private String attrType;

    /**
     * 字段类型
     */
    @NotNull(message = "字段类型不能为空")
    private Integer fieldType;

    /**
     * 标题
     */
    private String attrName;

    /**
     * 标题的英文
     */
    private String attrNameEn;

    /**
     * 图标
     */
    private String icon;
    /**
     * 描述信息
     */
    private String memo;

    /**
     * 是否允许编辑 1：允许 0：不允许
     */
    private Integer editable;
    /**
     * 是否允许可见 1:允许 0：不允许
     * 默认都可见
     */
    private Integer visible = 1;
    /**
     * 是否允许新增 1：允许 0：不允许
     */
    private Integer add;
    /**
     * 是否允许删除 1:允许 0：不允许
     */
    private Integer remove;
    /**
     *  是否启用可见高级设置 1:启用 0：不启用
     */
    private Integer visibleScopeEnable;
    /**
     * 是否启用编辑高级设置：1：启用 0：不启用
     */
    private Integer editableAdvanceEnable;
    /**
     * 是否启用新增高级设置：1：启用 0：不启用
     */
    private Integer addAdvanceEnable;
    /**
     * 是否启用删除高级设置：1：启用 0：不启用
     */
    private Integer removeAdvanceEnable;
    /**
     *  可见高级设置规则，格式{"type":1,"relative":[2],"role":[],"dep":[],"user":[]}
     */
    private VisibleRulePoJo visibleScopeRule;
    /**
     * 编辑高级设置规则，格式{"type":1,"relative":[2],"role":[],"dep":[],"user":[]}
     */
    private VisibleRulePoJo editableRule;
    /**
     * 新增高级设置规则，格式{"type":1,"relative":[2],"role":[],"dep":[],"user":[]}
     */
    private VisibleRulePoJo addRule;
    /**
     * 删除高级设置规则，格式{"type":1,"relative":[2],"role":[],"dep":[],"user":[]}
     */
    private VisibleRulePoJo removeRule;
    /**
     * 默认值属性
     */
    private DefaultAttrPoJo defaultAttr;

    /**
     * 不允许重复值 0:允许 1：不允许
     */
    private Integer noRepeat;

    /**
     * 客户名称全局判重： 0 不判重  1 模板内判重  2 客户全局判重 (参考 RepeatTypeEnum.java)
     */
    private Integer customerNameRepeatType;

    /**
     * 客户电话全局判重： 0 不判重  1 模板内判重  2 客户全局判重 (参考 RepeatTypeEnum.java)
     */
    private Integer customerPhoneRepeatType;
    /**
     * 自定义字段判重： 0 不判重  1 模板内判重  2 全局判重 (参考 RepeatTypeEnum.java)
     */
    private Integer customRepeatType;
    /**
     * 自定义字段全局判重规则。格式：[{"formId":"","attr":"text_1","fieldId":"2ae733bc-614f-4933-4905-39b2d88b70c0"}]
     */
    private  List<CustomRecheckRulePojo> customRecheckRules;
    /**
     * 是否必填 1:必填 0：选填
     */
    private Integer required;

    /**
     *  类型 手机号码：1 电话号码：2 邮政编码：3 身份证号码：4 邮箱：5
     */
    private Integer patternType;

    /**
     *  类型对应的正则表达式
     */
    private String verifyRule;
    /**
     * 正则表达式的提示信息
     */
    private String verifyMessage;
    /**
     * 仅允许填写整数 1：是 0：否
     */
    private Integer integerOnly;

    /**
     * 精度
     */
    private Integer accuracy;
    /**
     * 是否限制数值范围 1：限制；0：不限制
     */
    private Integer numericalLimitsFlag;
    /**
     * 数值限制范围
     */
    private NumericalLimitsPoJo numericalLimits;
    /**
     * 枚举值表示 格式 yyyy-MM-dd 或者 yyyy-MM-dd HH:mm:ss
     * @see DateTimeEnum
     */
    private String dateType;

    /**
     * 下拉框，下拉复选的选项(0:自定义 1：关联其他表单 2：数据联动  3：工商查询)
     * @see com.xbongbong.paas.enums.ComboTypeEnum
     */
    private Integer comboType;

    /**
     * 下拉框中的字典项标识，2：全都禁用 1：增加其他选项，0：不能增加其他选项  只有saas有，paas不用
     */
    private Integer dictionaryFlag;

    /**
     * 用于下拉框，下拉复选，单选，复选的选项值
     */
    @Size(max = 249, message = "当前选项超过了最大限制，请限制在249个")
    @Valid
    private List<ItemPoJo> items;


    private List<MultiUnitItemPoJo> multiItems;

    /**
     * 数据联动，但是现在的数据联动都在defaultAttr中
     */
    @Deprecated
    private RelyPoJo rely;

    /**
     *  关联其他表单
     */
    private LinkFormPoJo linkForm;
    /**
     * 线类型 虚线：dashed thin：细的实线 thick：粗的实线 nothing：无
     */
    private String lineType;
    /**
     * 是否需要显示详细地址 1：需要 0：不需要
     */
    private Integer showDetailAddress;
    /**
     * 是否显示经纬度 为 1/0
     */
    private Integer showLatAndLng;

    /**
     * 是否开启定位中心 1：是 0：否
     */
    private Integer locationCenterFlag;

    /**
     * 定位中心
     */
    private List<LocationCenterPoJo> locationCenter;

    /**
     * 微调
     */
    private TuningPoJo tuning;

    /**
     * 最大文件数量
     */
    private Integer maxFileCount;

    /**
     * 仅允许上传一张图片或者文件   1/0
     */
    private Integer onlyOneFile;

    /**
     * 仅允许拍照
     */
    private Integer onlyCamera;

    /**
     * 图片水印
     */
    private WatermarkPojo watermark;

    /**
     * 图片限制大小 MB
     */
    private Integer picSize;

    /**
     * 附件限制大小 MB
     */
    private Integer fileSize;

    /**
     * 图片限制开关 1/0
     */
    private Integer limitPicSize;

    /**
     * 附件限制开关 1/0
     */
    private Integer limitFileSize;

    /**
     *  1：打开外部窗口； 0：打开内部窗口
     */
    private Integer blank;

    /**
     * 自动压缩 1/0
     */
    private Integer autoCompress;

    /**
     * 子表单相关信息
     */
    private SubFormPoJo subForm;
    /**
     * 关联类型 linkedType为 0 表示PAAS应用内，为其他枚举类型表示关联的SAAS系统模块
     */
    private Integer linkedType;

    /**
     * 关联数据和关联查询的属性
     */
    private LinkInfoPojo linkInfo;

    /**
     * 可选范围
     */
    private LimitChooseRangePoJo limitChooseRange;
    /**
     * 存放特殊业务逻辑标识
     */
    private BusinessPojo businessPojo;

    /**
     * 流水编号设置
     */
    private SerialNumberPoJo serialNumber;

    /**
     * 严控模式(流水号)
     * 1 开启 0 不开启（默认）
     */
    private Integer strictController;
    /**
     * 是否是扩展字段 1：自定义字段；0：非自定义字段，即SaaS字段
     */
    private Integer isRedundant;

    /**
     * 排序字段
     */
    private Integer sort;

    /**
     * 汇总类型
     * @see com.xbongbong.pro.enums.SummaryTypeEnum
     */

    private Integer summaryFlag;

    /**
     * 数字字段为金额类型，1：是；0：不是
     * 金额的可能要特殊处理
     */
    private Integer amountFlag;

    /**
     * 关联成员
     * 存储数据为关联成员的attr
     */
    private String relatedMember;

    /**
     * 套餐字段限制标识
     *
     */
    private Integer packageLimit;

    /**
     * 是否在摘要中显示 1 显示 0 不显示
     */
    private Integer summary;

    /**
     * 选项联动
     */
    private JSONObject optionLinkage;



    // ======================Saas特殊属性========================
    /**
     * 对应saas中的attr
     */
    private String saasAttr;

    /**
     *  重命名、判重、启用必填等权限
     *  1.重命名+字段权限 必填显示且置灰
     *  2.重命名+字段权限+查重　必填显示且置灰
     *  3.重命名+字段权限+启用、必填
     *  4.重命名+字段权限+查重+启用、必填
     *  注：pro中启用和必填是同一个权限，同时启用或同时关闭
     */
    private Integer setType;

    /**
     *  模板设计阶段字段是否允许编辑
     *  1：允许编辑
     *  0：不允许编辑
     *  默认值：1
     */
    private Integer designEditable;

    /**
     *  字段在各个界面（新建、编辑、列表、详情）的展现形式，web端
     *  详见
     *  @see com.xbongbong.saas.enums.ShowTypeEnum
     *  默认值：0全部展示
     */
    private Integer showType;
    /**
     *  字段在各个界面（新建、编辑、列表、详情）的展现形式，手机端
     *  默认值：null
     *
     *  如果没有特殊情况，即手机端和web端展现形式相同，则该值为null，根据showType判断在app端的显隐；
     *  如果该属性有值，则证明该字段在app端的展现形式比较特殊，根据该属性判断在app端的显隐
     *  枚举值详见
     *  @see com.xbongbong.saas.enums.ShowTypeEnum
     */
    private Integer appShowType;

    /**
     *  字段是否显示在模板设计界面
     *  1：不显示
     *  0：显示
     */
    private Integer editHide;

    /**
     * 关联业务选择，关联字段
     */
    private String linkedText;

    /**
     * 默认开启 1:开启，0：关闭，2：回收站
     */
    private Integer isOpen;
    /**
     * saas特殊字段特有属性
     */
    private SaasParticularAttributePoJo saasParticularAttributePoJo;

    /**
     * 最大长度限制
     */
    private Integer maxLength;

    /**
     * 字符长度范围
     */
    private CharLimitsPoJo charLimits;

    /**
     * 是否可以连接详情
     */
    private LinkDetailPojo linkDetail;

    /**
     * 筛选类型
     * 1：可筛选
     * 2：不可筛选
     */
    private Integer screenType;

    /**
     * 标签attr
     */
    private String tagAttr;

    /**
     * 单据字段关联业务不唯一
     */
    private Integer isMultiBusiness;

    /**
     * 业务类型
     * 解析方案没有耦合业务，拿不到这玩意，期待更优解
     */
    private Integer businessType;

    private Boolean recentTime = false;
    /**
     *  当前开关对应的值需要关联的字段
     */
    private List<String> switchMap;
    /**
     *  是否支持扫描，0不支持，1支持
     */
    private Integer supportScanning;
    /**
     * 字段对应的智能助手个数（智能助手表没有条件不显示）
     */
    private Integer smartSettingsNum;

    /**
     * 区分单负责人和多负责人 1：多负责人 0：单负责人
     */
    private Integer multiple;

    /**
     * 是否数据字典
     */
    private Integer isDictionary;

    /**
     * saas曾用名
     */
    private String defaultName;
    /**
     * 不可编辑的字段描述
     */
    private String unableEditMemo;

    /**
     * 子表单字段中 父field属性
     */
    private FieldAttrEntity parentSubFormAttr;

    /**
     * 表单是否显示可新增
     */
    private Integer showAdd;
    /**
     * 表单是否显示可删除
     */
    private Integer showRemove;
    /**
     * 禁用列表排序 1禁用
     */
    private Integer disableListSort;

    /**
     * 是否允许被禁用 0为不允许
     * 资金3.0时，发现该字段还有一种用法：当该值为0时，关闭的字段不能再启用、启用的字段不能再关闭
     */
    private Integer isForbidden;

    /**
     * 高级设置是否隐藏，1隐藏
     */
    private Integer advancedSetHide;

    /**
     * 是否需要标红
     */
    private Integer redFlag;
    /**
     * 作废标记是否划很横线
     */
    private Integer cancelFlag;
    /**
     * 下拉不允许修改默认值，1不允许
     */
    private Integer itemBanDefault;
    /**
     * 是否字段权限处增加公海池选项，1显示
     */
    private Integer showPublicPool;
    /**
     * 公海池选项是否选择，1选择
     */
    private Integer publicPool;
    /**
     * 数字类型(NumberTypeEnum)
     */
    private String numberType;
    /**
     * 报价单新版本名称判重时，前端需要从名称字段解释里取后端需要的参数
     * 格式为{"newVersion": 1,"groupNumber": ""}
     */
    private JSONObject quotationNameRepeat;
    /**
     * 坏账是否划很横线
     */
    private Integer badFlag;


    /**
     * 控制关联选项不可编辑,默认为空或者是0，如果是需要控制的话就选1
     */
    private Integer noItemLink;

    private String batchType;
    /**
     * 子表单是否只能有一行
     */
    private Integer isSingleRow;

    /**
     * 永远不要set
     */
    private Integer noEditable;
    /**
     * 是否ALL字段权限的展示
     *
     * */
    private Integer showAttrPermission;
    /**
     * 字段权限-可编辑隐藏 0 隐藏
     */
    private Integer showEditable;
    /**
     * 字段权限-可见-高级设置 置灰
     * */
    private Integer  visibleAdvancedForbidden;
    /**
     * 字段权限-可编辑 置灰
     */
    private Integer editForbidden;
     /**
      * 数字精度和范围隐藏该项设置
      */
    private Integer  numAccuracyAndScopeHide;

     /**
      * 禁用设置列表
      * @see com.xbongbong.saas.enums.ForbiddenSettingEnum
      */
    private List<String>  forbiddenSettingList;
    /**
     * 可见权限，1可见，0不可见 不存库
     */
    private transient Integer hasJudgeVisible;

    /**
     * 列宽 子表单控件使用
     */
    private Long theWidth;

    /**
     * 宽度规格
     */
    private String widthAttr;

    /**
     * 冻结列的个数
     */
    private Long freezeCount;

    /**
     * 是否冻结
     * 默认都不冻结
     */
    private Boolean fixed = false;

    /*
     * 关联产品之间数据联动
     */
    private List<RelyPoJo> relyList;
    /**
     * 已选择的产品分类
     */
    private JSONArray selectedCategory;
    /**
     * 多单位有下游单据上游不可编辑
     */
    private Integer multiUnitNoEdit;

    /**
     * 数字是否使用千分符
     */
    private Integer groupingUsed;
    /**
     * 数字是否使用百分比
     */
    private Integer percentUsed;

    /**
     * 汇总方式
     */
    private String aggType;

    /**
     * 选择的日期展示格式 “yyyy-MM-dd E”等。原dateType前端用来判断“时间”和“日期”不同数据格式选项
     */
    private String chosenDateType;

    /**
     * 选择的日期分组格式 “yyyy-MM-dd E”等。
     */
    private String dateGroupType;

    /**
     * 表头显示字段
     */
    private String label;

    /**
     * 表头显示字段
     */
    private String labelName;

    /**
     * saas标志
     */
    private Integer saasMark;
    /**
     * 字段最小允许的列宽
     */
    private Integer minColumnWidth;

    /**
     * 字段当前列宽
     */
    private Integer columnWidth;
    // private Integer attrNameTransferFlag;
    //
    // private Integer attrNameEnTransferFlag;

    /**
     * 关联业务是否是经销商
     */
    private Integer distributorMark;

    /**
     * 仅允许上传一张图片或者文件　1置灰
     */
    private Integer onlyOneFileForbidden;

    /**
     * 电话字段 是否开启电话掩码 1表示开启 0表示未开启
     */
    private Integer isMaskTelephone;

    /**
     * 负责人字段是否唯一标识，0不唯一，1唯一
     */
    private Integer unique;

    /**
     * 协同人字段表单权限设置，0只读，1可编辑
     */
    private Integer formPermission;

    /**
     * 图表钻取功能使用 - 图表设计处
     * 该值为1，字段右侧才有“···”，否则无“···”。“···”点击后默认有“创建层级关系”按钮，“添加到层级”按钮显隐前端结合层级列表接口控制
     */
    private Integer drill;
    /**
     * 图表钻取功能使用 - 图表设计处
     * 值为空代表非钻取层级字段，非空代表层级字段，且值为对应层级的uuid
     */
    private String drillUuid;
    /**
     * 数据集id 可为空
     */
    private Long dataSetId;
    /**
     * 连接节点背景颜色
     */
    private String bgColor;
    /**
     * 根据是否合并连接字段，控制合并字段。左连接左表连接字段启用、右连接右表连接字段启用，内连接左表连接字段启用
     * 为空或为1代表需要恒显示，非1代表当合并连接字段时，该字段需隐藏
     * 对于数据集来说{@link com.xbongbong.paas.enums.bi.DataSetFieldStatusEnum}
     */
    private Integer status;

    /**
     * 是否开启阶段推进器多版本启用，0不是，1是
     */
    private Integer stageMultiVersion;

    /**
     * 开启了阶段推进器多版本启用后设置的默认版本
     */
    private Long defaultStageProcessId;

    // ======================Saas特殊属性========================

    public FieldAttrEntity(){
        isRedundant = 1;
        isOpen = 1;
//        parentAttr = "";
        dateType = DateTimeEnum.DATETIME.getType();
//        designEditable = 1;
//        maxFileCount = 9;
//        accuracy = 4;
//        multiple = 0;
        editableRule = new VisibleRulePoJo();
//        editableAdvanceEnable = 0;
//        numericalLimitsFlag = 0;
        defaultAttr = new DefaultAttrPoJo();
        redFlag = 0;
        cancelFlag = 0;
        isSingleRow = 0;
        noEditable = 0;
        strictController = 0;
    }

    @Override
    public int compareTo(FieldAttrEntity o) {
        return this.sort - o.getSort();
    }

    /**
     * 比较字段是否更改，目前只比较了部分字段
     * @param entity 被比较的实体
     * @return boolean
     * @author zcp
     * @date 2019/6/30 20:05
     * @since v1.0
     * @version v1.0
     */
    public boolean change(FieldAttrEntity entity){
        boolean flag = !Objects.equals(attrName, entity.attrName) || !Objects.equals(memo, entity.memo) || !Objects.equals(editable, entity.editable) || !Objects.equals(editableAdvanceEnable, entity.editableAdvanceEnable)
                || !Objects.equals(visible, entity.visible) || !Objects.equals(visibleScopeEnable, entity.visibleScopeEnable) || !Objects.equals(noRepeat, entity.noRepeat) || !Objects.equals(required, entity.required)
                || !Objects.equals(patternType, entity.patternType) || !Objects.equals(integerOnly, entity.integerOnly) || !Objects.equals(accuracy, entity.accuracy) || !Objects.equals(numericalLimitsFlag, entity.numericalLimitsFlag)
                || !Objects.equals(dateType, entity.dateType) || !Objects.equals(comboType, entity.comboType) || !Objects.equals(lineType, entity.lineType) || !Objects.equals(showDetailAddress, entity.showDetailAddress)
                || !Objects.equals(showLatAndLng, entity.showLatAndLng) || !Objects.equals(locationCenterFlag, entity.locationCenterFlag) || !Objects.equals(maxFileCount, entity.maxFileCount) || !Objects.equals(onlyOneFile, entity.onlyOneFile)
                || !Objects.equals(onlyCamera, entity.onlyCamera) || !Objects.equals(autoCompress, entity.autoCompress) || !Objects.equals(summaryFlag, entity.summaryFlag) || !Objects.equals(amountFlag, entity.amountFlag)
                || !Objects.equals(setType, entity.setType);

        if (flag) {
            //已经有更新了，则后面的无需判断
            return flag;
        }
        //定位设置
        TuningPoJo tuningOld = tuning == null ? new TuningPoJo() : tuning;
        TuningPoJo tuningNew = entity.tuning == null ? new TuningPoJo() : entity.tuning;
        flag = !Objects.equals(tuningOld.getEnable(), tuningNew.getEnable()) || !Objects.equals(tuningOld.getRadius(), tuningNew.getRadius());
        if (flag) {
            //已经有更新了，则后面的无需判断
            return flag;
        }

        return flag;
    }

    public void setNoEditable(Integer noEditable) {
        if (Objects.isNull(noEditable)){
            return;
        }
        this.noEditable = noEditable;
    }

    public String getAttrName() {
        Locale locale = LocaleContextHolder.getLocale();
        if (Objects.equals(locale.getLanguage(), I18nStringConstant.ENGLISH_LANGUAGE)&& StringUtils.isNotEmpty(attrNameEn)) {
            return attrNameEn;
        }
        return attrName;
    }

    /**
     * 国际化修改attrName 与 attrName_en
     *  特殊场景专用
     * @return
     */
    public void changeAttrName() {
        Locale locale = LocaleContextHolder.getLocale();
        if (Objects.equals(locale.getLanguage(), I18nStringConstant.ENGLISH_LANGUAGE)&& StringUtils.isNotEmpty(attrNameEn)) {
            String replace = attrName;
            attrName = attrNameEn;
            attrNameEn = replace;
        }

    }
    public String getAttrNameEn() {
        Locale locale = LocaleContextHolder.getLocale();
        if (Objects.equals(locale.getLanguage(), I18nStringConstant.ENGLISH_LANGUAGE)) {
            return attrName;
        }
        return attrNameEn;
    }

    /**
     * 是否是比率相关字段
     * @return
     */
    public static boolean isRate(String saasAttr, String numberType) {
        return Objects.equals(ContractEnum.GROSS_PROFIT_RATE.getSaasAttr(), saasAttr)
                || Objects.equals(ContractEnum.CASH_PROFIT_RATE.getSaasAttr(), saasAttr)
                || Objects.equals(ContractEnum.PAY_PERCENT.getSaasAttr(), saasAttr)
                || Objects.equals(SalesOpportunityEnum.GROSS_PROFIT_RATE.getSaasAttr(), saasAttr)
                || Objects.equals(QuotationEnum.GROSS_PROFIT_RATE.getSaasAttr(), saasAttr)
                || Objects.equals(PurchaseEnum.RECEINE_PERCENT.getSaasAttr(), saasAttr)
                || Objects.equals(numberType, NumberTypeEnum.RATE.getCode());
    }
}
